package org.example;

import org.apache.pekko.actor.ActorRef;
import org.apache.pekko.actor.ActorSelection;
import org.apache.pekko.dispatch.OnComplete;
import org.apache.pekko.pattern.Patterns;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.time.Duration;
import java.util.Arrays;
import java.util.Map;

import org.apache.pekko.util.Timeout;
import scala.concurrent.ExecutionContext;
import scala.concurrent.Future;

public interface ExecuteExpression {
    Object execute(String expression , Map<String,Object> paras);
    class Builder{
        public ExecuteExpression builder(ActorSelection actorSelection){
            InvocationHandler invocationHandler = new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println(Arrays.toString(args));
                    Message msg = new Message(method.getName() , MessageType.DATA , args , new Class[]{String.class , Map.class});
                    return handleRpc(msg);
                }
                public Object handleRpc(Message msg){
                    if(msg.getType().equals(MessageType.DATA)){
                        System.out.println("send data");
//                        Future<Object> ask = Patterns.ask(actorSelection, msg.getMessage()
//                                , Timeout.create(Duration.ofSeconds(2)));
                        actorSelection.tell(msg ,ActorRef.noSender());
//                        ask.onComplete(
//                                new OnComplete<Object>() {
//                                    @Override
//                                    public void onComplete(Throwable failure, Object success) {
//                                        if (failure != null) {
//                                            System.out.println(failure);
//                                        } else {
//                                            System.out.println(success);
//                                        }
//                                    }
//                                },
//                                DirectExecutionContext.INSTANCE);
                        }
                    return null ;
                }
            };
            ExecuteExpression o = (ExecuteExpression)Proxy.newProxyInstance(ExecuteExpression.class.getClassLoader()
                    , new Class[]{ExecuteExpression.class}
                    , invocationHandler
            );
            return o ;
        }
    }

    class DirectExecutionContext implements ExecutionContext {

        static final DirectExecutionContext INSTANCE = new DirectExecutionContext();

        private DirectExecutionContext() {}

        @Override
        public void execute(Runnable runnable) {
            runnable.run();
        }

        @Override
        public void reportFailure(Throwable cause) {
            throw new IllegalStateException("Error in direct execution context.", cause);
        }

        @Override
        public ExecutionContext prepare() {
            return this;
        }
    }
}
